#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
新浪财经历史分红数据预处理工具
该工具用于读取爬取的新浪财经历史分红数据，进行数据预处理，并保存处理后的数据
"""

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler

class SinaDividendPreprocessor:
    """新浪财经历史分红数据预处理类"""
    
    def __init__(self, input_file="新浪财经历史分红数据.xlsx", 
                 output_file="新浪财经历史分红数据_预处理.xlsx"):
        """
        初始化预处理工具
        
        Args:
            input_file (str): 输入的Excel文件路径
            output_file (str): 输出的Excel文件路径
        """
        self.input_file = input_file
        self.output_file = output_file
        self.data = None
        self.processed_data = None
    
    def load_data(self):
        """\加载Excel数据"""
        try:
            self.data = pd.read_excel(self.input_file)
            print(f"成功加载数据，文件: {self.input_file}")
            return True
        except Exception as e:
            print(f"加载数据时出错: {str(e)}")
            print(f"请确保文件 '{self.input_file}' 存在于当前目录或提供正确的文件路径")
            return False
    
    def check_data_shape(self):
        """检查数据形状"""
        if self.data is None:
            print("数据未加载")
            return
        
        print(f"数据形状: {self.data.shape}")
        print(f"数据列名: {list(self.data.columns)}")
    
    def check_duplicates(self):
        """检查指定列的重复值"""
        if self.data is None:
            print("数据未加载")
            return
        
        columns_to_check = ['代码', '名称', '详细']
        
        for col in columns_to_check:
            if col in self.data.columns:
                duplicate_count = self.data[col].duplicated().sum()
                print(f"'{col}'列中的重复值数量: {duplicate_count}")
                
                # 显示前5个重复值的例子
                if duplicate_count > 0:
                    duplicates = self.data[self.data[col].duplicated(keep=False)]
                    print(f"'{col}'列中的重复值示例（前5行）:")
                    print(duplicates.head(5)[col])
                    print()
            else:
                print(f"列 '{col}' 不存在于数据中")
    
    def show_first_five_rows(self):
        """展示数据前5行"""
        if self.data is None:
            print("数据未加载")
            return
        
        print("数据前5行:")
        print(self.data.head())
        print()
        
        # 观察数据可能存在的问题
        print("数据基本信息:")
        print(self.data.info())
        print()
        
        print("数据统计摘要:")
        print(self.data.describe(include='all'))
        print()
    
    def process_listing_date(self):
        """处理上市日期，提取年、月、日变量"""
        if self.data is None:
            print("数据未加载")
            return
        
        if '上市日期' in self.data.columns:
            # 创建一个副本，避免直接修改原始数据
            self.processed_data = self.data.copy()
            
            # 尝试转换为日期类型
            try:
                # 处理可能的缺失值或无效日期
                self.processed_data['上市日期'] = pd.to_datetime(
                    self.processed_data['上市日期'], 
                    errors='coerce'
                )
                
                # 提取年、月、日
                self.processed_data['上市年份'] = self.processed_data['上市日期'].dt.year
                self.processed_data['上市月份'] = self.processed_data['上市日期'].dt.month
                self.processed_data['上市日'] = self.processed_data['上市日期'].dt.day
                
                print("已成功处理上市日期并提取年、月、日变量")
            except Exception as e:
                print(f"处理上市日期时出错: {str(e)}")
        else:
            print("列 '上市日期' 不存在于数据中")
    
    def normalize_numeric_variables(self):
        """对数值型变量进行归一化处理"""
        if self.processed_data is None:
            print("数据尚未进行初步处理")
            return
        
        numeric_columns = ['累计股息(%)', '年均股息(%)', '分红次数', '融资总额(亿)']
        valid_columns = []
        
        # 检查并准备数值型数据
        for col in numeric_columns:
            if col in self.processed_data.columns:
                try:
                    # 尝试转换为数值型
                    self.processed_data[col] = pd.to_numeric(
                        self.processed_data[col], 
                        errors='coerce'
                    )
                    valid_columns.append(col)
                except Exception as e:
                    print(f"转换列 '{col}' 为数值型时出错: {str(e)}")
            else:
                print(f"列 '{col}' 不存在于数据中")
        
        if not valid_columns:
            print("没有有效的数值型列可以进行归一化处理")
            return
        
        try:
            # 使用MinMaxScaler进行归一化
            scaler = MinMaxScaler()
            normalized_data = scaler.fit_transform(
                self.processed_data[valid_columns].fillna(0)  # 用0填充缺失值
            )
            
            # 创建归一化后的列名
            normalized_columns = [f'{col}_归一化' for col in valid_columns]
            
            # 将归一化后的数据添加到处理后的数据中
            normalized_df = pd.DataFrame(normalized_data, columns=normalized_columns)
            self.processed_data = pd.concat([self.processed_data, normalized_df], axis=1)
            
            print(f"已成功对以下列进行归一化处理: {', '.join(valid_columns)}")
        except Exception as e:
            print(f"进行数据归一化时出错: {str(e)}")
    
    def save_processed_data(self):
        """保存预处理后的数据"""
        if self.processed_data is None:
            print("没有预处理后的数据可供保存")
            return
        
        try:
            self.processed_data.to_excel(self.output_file, index=False, engine='openpyxl')
            print(f"预处理后的数据已成功保存到: {self.output_file}")
        except Exception as e:
            print(f"保存预处理后的数据时出错: {str(e)}")
    
    def run(self):
        """运行预处理的主方法"""
        print("开始预处理新浪财经历史分红数据")
        
        # 步骤1: 加载数据
        if not self.load_data():
            return
        
        # 步骤2: 检查数据形状和重复值
        self.check_data_shape()
        self.check_duplicates()
        
        # 步骤3: 展示数据前5行
        self.show_first_five_rows()
        
        # 步骤4: 处理上市日期
        self.process_listing_date()
        
        # 步骤5: 归一化数值型变量
        self.normalize_numeric_variables()
        
        # 步骤6: 保存预处理后的数据
        self.save_processed_data()
        
        print("数据预处理完成")

if __name__ == "__main__":
    # 检查是否已安装必要的依赖包
    try:
        import pandas
        import numpy
        import sklearn
        import openpyxl
    except ImportError:
        print("检测到缺少必要的依赖包，建议先安装：")
        print("pip install pandas numpy scikit-learn openpyxl")
    
    # 创建预处理实例并运行
    preprocessor = SinaDividendPreprocessor()
    preprocessor.run()